//#define USE_DUNGEONBUDDY_DLL
using System.Collections.Generic;
using System.Linq;
using CommonBehaviors.Actions;
using Styx;
using Styx.CommonBot;
using Styx.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.TreeSharp;
#if USE_DUNGEONBUDDY_DLL
using Bots.DungeonBuddyDll;
using Bots.DungeonBuddyDll.Profiles;
using Bots.DungeonBuddyDll.Attributes;
using Bots.DungeonBuddyDll.Helpers;

namespace Bots.DungeonBuddyDll.Dungeon_Scripts.Wrath_of_the_Lich_King
#else
    using Bots.DungeonBuddy.Profiles;
    using Bots.DungeonBuddy.Attributes;
    using Bots.DungeonBuddy.Helpers;
namespace Bots.DungeonBuddy.Dungeon_Scripts.Wrath_of_the_Lich_King
#endif
{
    public class UtgardePinnacle : Dungeon
    {
        #region Overrides of Dungeon

        public override uint DungeonId
        {
            get { return 203; }
        }

        public override WoWPoint Entrance
        {
            get { return new WoWPoint(-11522.1f, -2316.38f, 608.393f); }
        }

        public override WoWPoint ExitLocation
        {
            get { return new WoWPoint(-328f, 24.8f, 626.979f); }
        }

        public override void RemoveTargetsFilter(List<WoWObject> units)
        {
            units.RemoveAll(
                ret =>
                {
                    if (ret.Entry == DragonflayerSpectatorId)
                        return true;
                    if (ret.Entry == GraufId)
                        return true;
                    if (ret.Entry == SkadiId && (ret.ToUnit().HasAura("Ride Vehicle") || ret.ToUnit().HasAura("Whirlwind") && Me.IsDps() && Me.IsMelee()))
                        return true;
                    return false;
                });
        }

        public override void IncludeTargetsFilter(List<WoWObject> incomingunits, HashSet<WoWObject> outgoingunits)
        {
            foreach (var obj in incomingunits)
            {
                var unit = obj as WoWUnit;
                if (unit != null) { }
            }
        }

        public override void WeighTargetsFilter(List<Targeting.TargetPriority> units)
        {
            foreach (var priority in units)
            {
                var unit = priority.Object as WoWUnit;
                if (unit != null)
                {
                    if (unit.Entry == RitualChannelerId)
                        priority.Score += 500;
                    if (unit.Entry == DragonflayerSeerId && StyxWoW.Me.IsDps())
                        priority.Score += 500;
                }
            }
        }

        #endregion

        private WoWUnit _skadi;
        private const uint RitualChannelerId = 27281;
        const uint DragonflayerSeerId = 26554;
        private const uint DragonflayerSpectatorId = 26667;
        private const uint GraufId = 26893;
        private const uint SkadiId = 26693;

        private LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        [EncounterHandler(30871, "Brigg Smallshanks", Mode = CallBehaviorMode.Proximity, BossRange = 30)]
        public Composite QuestPickupHandler()
        {
            WoWUnit unit = null;
            const int vengeanceBeMineQuestId = 13132;

            return new PrioritySelector(
                ctx => unit = ctx as WoWUnit,
                new Decorator(
                    ctx => !Me.Combat && !ScriptHelpers.WillPullAggroAtLocation(unit.Location) && unit.QuestGiverStatus == QuestGiverStatus.Available,
                    new PrioritySelector(
                        new Decorator(
                            ctx => !Me.QuestLog.ContainsQuest(vengeanceBeMineQuestId) && !Me.QuestLog.GetCompletedQuests().Contains(vengeanceBeMineQuestId),
                            ScriptHelpers.CreatePickupQuest(() => unit, vengeanceBeMineQuestId)))),
                new Decorator(
                    ctx => !Me.Combat && !ScriptHelpers.WillPullAggroAtLocation(unit.Location) && unit.QuestGiverStatus == QuestGiverStatus.TurnIn,
                    ScriptHelpers.CreateTurninQuest(() => unit)));
        }

        [EncounterHandler(56072, "Image of Argent Confessor Paletress", Mode = CallBehaviorMode.Proximity, BossRange = 35)]
        public Composite QuestPickupHandler2()
        {
            WoWUnit unit = null;
            return new PrioritySelector(
                ctx => unit = ctx as WoWUnit,
                new Decorator(
                    ctx => !Me.Combat && !ScriptHelpers.WillPullAggroAtLocation(unit.Location) && unit.QuestGiverStatus == QuestGiverStatus.Available,
                    ScriptHelpers.CreatePickupQuest(() => unit)),
                new Decorator(
                    ctx => !Me.Combat && !ScriptHelpers.WillPullAggroAtLocation(unit.Location) && unit.QuestGiverStatus == QuestGiverStatus.TurnIn,
                    ScriptHelpers.CreateTurninQuest(() => unit)));
        }

        [EncounterHandler(26668, "Svala Sorrowgrave", Mode = CallBehaviorMode.CurrentBoss)]
        public Composite SvalaSorrowgraveEncounter()
        {
            WoWUnit sorrowgrave = null, svala = null;
            const uint ritualTargetId = 27327;
            const int ritualOfTheSwordId = 48276;

            AddAvoidObject(
                ctx => !Me.IsTank() && sorrowgrave != null && sorrowgrave.IsValid && (sorrowgrave.CastingSpellId == ritualOfTheSwordId || sorrowgrave.ChanneledCastingSpellId == ritualOfTheSwordId),
                10,
                o => o.Entry == ritualTargetId && !ScriptHelpers.GetUnfriendlyNpsAtLocation(() => o.Location, 30, u => u.Entry == RitualChannelerId).Any());

            return new PrioritySelector(
                ctx =>
                {
                    svala = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == 29281);
                    return sorrowgrave = ctx as WoWUnit;
                },
                // wait for the bitch to spawn. 
                new Decorator(
                    ctx =>
                    ((svala != null && svala.DistanceSqr <= 10 * 10) || (sorrowgrave != null && !sorrowgrave.Attackable && sorrowgrave.DistanceSqr <= 10 * 10)) &&
                    StyxWoW.Me.IsTank() && !StyxWoW.Me.IsActuallyInCombat,
                    new ActionAlwaysSucceed()));
        }

        [ObjectHandler(188593, "Stasis Generator")]
        public Composite StasisGeneratorHandler()
        {
            WoWGameObject generator = null;
            return new PrioritySelector(
                ctx => generator = ctx as WoWGameObject,
                new Decorator(
                    ctx => StyxWoW.Me.IsTank() && Targeting.Instance.IsEmpty() && generator.CanUse(),
                    ScriptHelpers.CreateInteractWithObject(() => generator, 12, false)));
        }

        [EncounterHandler(26685, "Massive Jormungar")]
        public Composite MassiveJormungarEncounter()
        {
            WoWUnit boss = null;
            return new PrioritySelector(
                ctx => boss = ctx as WoWUnit,
                // frontal spray. 
                ScriptHelpers.CreateAvoidUnitAnglesBehavior(ctx => !Me.IsTank() && boss.CurrentTargetGuid != Me.Guid && !boss.IsMoving && boss.Distance < 15, () => boss, new ScriptHelpers.AngleSpan(0, 180)),
                ScriptHelpers.CreateTankFaceAwayGroupUnit(15)
                );
        }

        [EncounterHandler(26687, "Gortok Palehoof")]
        public Composite GortokPalehoofEncounter()
        {
            WoWUnit boss = null;
            return new PrioritySelector(
                ctx => boss = ctx as WoWUnit,
                // cleave
                ScriptHelpers.CreateAvoidUnitAnglesBehavior(ctx => !Me.IsTank() && boss.CurrentTargetGuid != Me.Guid && !boss.IsMoving && boss.Distance < 8, () => boss, new ScriptHelpers.AngleSpan(0, 180)),
                ScriptHelpers.CreateTankFaceAwayGroupUnit(8)
                );
        }

        [EncounterHandler(26693, "Skadi the Ruthless", Mode = CallBehaviorMode.CurrentBoss)]
        public Composite SkadiTheRuthlessEncounter()
        {
            WoWUnit grauf = null;
            WoWDynamicObject freezingCloud = null;
            WoWGameObject harpoon = null, harpoonLancher = null;
            var throwHarpoonsLoc = new WoWPoint(520.4827, -541.5633, 119.8416);
            var tankSpot = new WoWPoint(486.1297, -515.4338, 104.723);
            AddAvoidObject(ctx => !Me.IsTank(), o => Me.IsRange() && Me.IsMoving ? 15 : 10, o => o.Entry == SkadiId && (o.ToUnit().HasAura("Whirlwind") || Me.IsRange()));

            return new PrioritySelector(
                ctx => _skadi = ctx as WoWUnit,
                // boss is in the air
                new Decorator(
                // boss is flying around and sometimes drops out of object manager
                    ctx => (_skadi != null && _skadi.HasAura("Ride Vehicle")) || (_skadi == null && StyxWoW.Me.Y < -475),
                    new PrioritySelector(
                        ctx =>
                        {
                            freezingCloud = ObjectManager.GetObjectsOfType<WoWDynamicObject>().FirstOrDefault(o => o.Entry == 47579);
                            harpoon = ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.Entry == 192539).OrderBy(o => o.DistanceSqr).FirstOrDefault();
                            harpoonLancher =
                                ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.Entry == 192176 && o.CanUse()).OrderBy(o => o.DistanceSqr).FirstOrDefault();
                            grauf = ObjectManager.GetObjectsOfType<WoWUnit>().FirstOrDefault(u => u.Entry == 26893 && u.IsAlive);
                            return ctx;
                        },
                // freezing cloud is on west/left side.
                        new Decorator(
                            ctx => freezingCloud != null && freezingCloud.Y >= -512 && StyxWoW.Me.Y > -516 && StyxWoW.Me.Y < -492,
                            new Action(
                                ctx =>
                                {
                                    var moveToLoc = StyxWoW.Me.Location;
                                    moveToLoc.Y = -516.5f;
                                    WoWMovement.ClickToMove(moveToLoc);
                                })),
                // freezing cloud is on east/right side
                        new Decorator(
                            ctx => freezingCloud != null && freezingCloud.Y < -512 && StyxWoW.Me.Y < -510.5,
                            new Action(
                                ctx =>
                                {
                                    var moveToLoc = StyxWoW.Me.Location;
                                    moveToLoc.Y = -510f;
                                    WoWMovement.ClickToMove(moveToLoc);
                                })),
                // only have the dps pick up the harpoons and only when there is no freezing cloud on ground.
                        new Decorator(ctx => harpoon != null && freezingCloud == null && StyxWoW.Me.IsDps(), ScriptHelpers.CreateInteractWithObject(() => harpoon, 0, true)),
                // check if shadi is in front of the harpoons and if we have any harpoons..
                        new Decorator(
                            ctx =>
                            grauf != null && grauf.Location.DistanceSqr(throwHarpoonsLoc) <= 20 * 20 && harpoonLancher != null && StyxWoW.Me.BagItems.Any(i => i.Entry == 37372),
                            ScriptHelpers.CreateInteractWithObject(() => harpoonLancher)),
                // move towards the end of the gauntlet
                        new Decorator(ctx => StyxWoW.Me.IsTank() && StyxWoW.Me.Location.DistanceSqr(tankSpot) > 15 * 15, new Action(ctx => ScriptHelpers.MoveTankTo(tankSpot))))),
                // boss is on the ground. 
                new Decorator(
                    ctx => _skadi != null && !_skadi.HasAura("Ride Vehicle"),
                    new PrioritySelector(
                        new Decorator(ctx => StyxWoW.Me.IsTank() && _skadi.CurrentTargetGuid == Me.Guid, ScriptHelpers.CreateTankUnitAtLocation(() => tankSpot, 5)))));
        }

        [EncounterHandler(26861, "King Ymiron")]
        public Composite KingYmironEncounter()
        {
            const uint spiritFountId = 27339;
            AddAvoidObject(ctx => true, o => Me.IsMoving && Me.IsRange() ? 15 : 10, spiritFountId);

            WoWUnit boss = null;
            return new PrioritySelector(
                ctx => boss = ctx as WoWUnit,
                ScriptHelpers.CreateDispellEnemy("Bane", ScriptHelpers.EnemyDispellType.Magic, () => boss));
        }

    }
}